{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 改变对象的字符串显示\n",
    "#要改变一个实例的字符串表示，可重新定义它的 __str__() 和 __repr__() 方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Pair:\n",
    "    def __init__(self,x,y):\n",
    "        self.x=x\n",
    "        self.y=y\n",
    "    def __str__(self):\n",
    "        return '({0.x!s},{0.y!s})'.format(self)\n",
    "    \n",
    "    def __repr__(self):\n",
    "        return 'Pair({0.x!s},{0.y!s})'.format(self)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "p=Pair(3,3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3,3)\n"
     ]
    }
   ],
   "source": [
    "print(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Pair(3,3)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "#自定义字符串的格式化\n",
    "#__format__() 方法给 Python 的字符串格式化功能提供了一个钩子。\n",
    "#这里需要着 重强调的是格式化代码的解析工作完全由类自己决定。因此，格式化代码可以是任何值\n",
    "_formats={\n",
    "    'ymd':'{d.year}-{d.month}-{d.day}',\n",
    "    'mdy':'{d.month}-{d.day}:{d.year}'\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dates:\n",
    "    def __init__(self,year,month,day):\n",
    "        self.year=year\n",
    "        self.month=month\n",
    "        self.day=day\n",
    "    def __format__(self,code):\n",
    "        if code=='':\n",
    "            code='ymd'\n",
    "        fmt=_formats[code]\n",
    "        return fmt.format(d=self)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "d=Dates(2019,1,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2019-1-1'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "format(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1-1:2019'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "format(d,'mdy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 让对象支持上下文管理-with语句\n",
    "# 为了让一个对象兼容 with 语句，你需要实现 __enter__() 和 __exit__() 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建大量对象时节省内存方法  \n",
    "对于主要是用来当成简单的数据结构的类而言，你可以通过给类添加 __slots__ 属性来极大的减少实例所占的内存"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dates:\n",
    "    __slots__=['year','month','day']\n",
    "    def __init__(self,year,month,day):\n",
    "        self.year=year\n",
    "        self.month=month\n",
    "        self.day=day"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "当你定义 __slots__ 后，Python 就会为实例使用一种更加紧凑的内部表示。\n",
    "实 例通过一个很小的固定大小的数组来构建，而不是为每个实例定义一个字典，这跟元 组或列表很类似。\n",
    "在 __slots__ 中列出的属性名在内部被映射到这个数组的指定小标 上。\n",
    "使用 slots 一个不好的地方就是我们不能再给实例添加新的属性了，只能使用在 __slots__ 中定义的那些属性名。\n",
    "\n",
    "使用 slots 后节省的内存会跟存储属性的数量和类型有关。\n",
    "不过，一般来讲，使用 到的内存总量和将数据存储在一个元组中差不多。\n",
    "为了给你一个直观认识，假设你不使 用 slots 直接存储一个 Date 实例，\n",
    "在 64 位的 Python 上面要占用 428 字节，而如果使 用了 slots，内存占用下降到 156 字节。\n",
    "如果程序中需要同时创建大量的日期实例，那 么这个就能极大的减小内存使用量了。 \n",
    "尽管 slots 看上去是一个很有用的特性，很多时候你还是得减少对它的使用冲动。 \n",
    "Python 的很多特性都依赖于普通的基于字典的实现。\n",
    "另外，定义了 slots 后的类不再支 持一些普通类特性了，比如多继承。\n",
    "大多数情况下，你应该只在那些经常被使用到的用 作数据结构的类上定义 slots (比如在程序中需要创建某个类的几百万个实例对象)。 \n",
    "关于 __slots__ 的一个常见误区是它可以作为一个封装工具来防止用户给实例增 加新的属性。\n",
    "尽管使用slots可以达到这样的目的，但是这个并不是它的初衷。__slots__ 更多的是用来作为一个内存优化工具。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "#在类中封装属性名\n",
    "#你想封装类的实例上面的“私有”数据，但是 Python 语言并没有访问控制。\n",
    "class A:\n",
    "    def __init__(self):\n",
    "        self.pulic=1\n",
    "        self._internal=0\n",
    "    def public_method(self):\n",
    "        pass\n",
    "    def _internal_method(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#你想给某个实例 attribute 增加除访问与修改之外的其他处理逻辑，比如类型检查 或合法性验证。\n",
    "#自定义某个属性的一种简单方法是将它定义为一个 property\n",
    "class Person:\n",
    "    def __init__(self,name):\n",
    "        self.name=name\n",
    "    @property\n",
    "    def name(self):\n",
    "        return self._name\n",
    "    @name.setter\n",
    "    def name(self,value):\n",
    "        if not isinstance(value,str):\n",
    "            raise TypeError(\"Expected a string\")\n",
    "        self._name=value\n",
    "    @name.deleter\n",
    "    def name(self):\n",
    "        raise AttributeError(\"Can't delete attribute\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "a=Person(\"Bo\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bo'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "Expected a string",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-5-04544bb90e59>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ma\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32m<ipython-input-2-57216391283f>\u001b[0m in \u001b[0;36mname\u001b[1;34m(self, value)\u001b[0m\n\u001b[0;32m     10\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     11\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 12\u001b[1;33m             \u001b[1;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Expected a string\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     13\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_name\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     14\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdeleter\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: Expected a string"
     ]
    }
   ],
   "source": [
    "a.name=1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "Can't delete attribute",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-6-a495b342d7d6>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mdel\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32m<ipython-input-2-57216391283f>\u001b[0m in \u001b[0;36mname\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m     14\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdeleter\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m         \u001b[1;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Can't delete attribute\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: Can't delete attribute"
     ]
    }
   ],
   "source": [
    "del a.name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在实现一个property的时候,底层数据仍然需要存储在某个地方.因此在get和set方法中,需要对name进行操作.这也是实际数据保存的地方."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Person:\n",
    "    def __init__(self,name):\n",
    "        self.set_name(name)\n",
    "    def get_name(self):\n",
    "        return self._name\n",
    "    def set_name(self,vals):\n",
    "        if not isinstance(vals,str):\n",
    "            raise TypeError(\"Excepted a string\")\n",
    "        self._name=vals\n",
    "    def del_name(self):\n",
    "        raise AttributeError(\"Can't delete attribute\")\n",
    "    name=property(get_name,set_name,del_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 调用父类方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "class A:\n",
    "    def func1(self):\n",
    "        print(\"A\")\n",
    "class B(A):\n",
    "    def func1(self):\n",
    "        print(\"B\")\n",
    "        super().func1()\n",
    "        #为了调用父类 (超类) 的一个方法，可以使用 super() 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "a1=B()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "B\n",
      "A\n"
     ]
    }
   ],
   "source": [
    "a1.func1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "#super() 函数的一个常见用法是在 __init__() 方法中确保父类被正确的初始化了\n",
    "class A:\n",
    "    def __init__(self):\n",
    "        self.x=1\n",
    "class B(A):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.y=1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "#super() 的另外一个常见用法出现在覆盖 Python 特殊方法的代码中\n",
    "class Proxy:\n",
    "    def __init__(self,obj):\n",
    "        self._obj=obj\n",
    "    def __getattr__(self,name):\n",
    "        return getattr(self._obj,name)\n",
    "    def __setattr__(self,name,value):\n",
    "        if name.startswith('_'):\n",
    "            super().__init__(name,value)\n",
    "        else:\n",
    "            setattr(self._obj,name,value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
